﻿using System;
using fastCSharp;
using fastCSharp.code.cSharp;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using fastCSharp.threading;
using System.Threading;
using fastCSharp.net;

namespace diantou.webSocket.exam
{
    /// <summary>
    /// 图片上传
    /// </summary>
    [fastCSharp.code.cSharp.webSocket]
    partial class image : user<image>
    {
        /// <summary>
        /// 考试用户上传图片信息
        /// </summary>
        private struct upload
        {
            /// <summary>
            /// 可上传图片时间
            /// </summary>
            public DateTime Time;
            /// <summary>
            /// 是否可上传图片
            /// </summary>
            public bool IsTime
            {
                get { return Time != DateTime.MinValue && Time <= date.NowSecond; }
            }
            /// <summary>
            /// 图片路径
            /// </summary>
            public string Path;
            /// <summary>
            /// 文件名称
            /// </summary>
            public int FileName;
            /// <summary>
            /// 初始化图片路径
            /// </summary>
            /// <param name="path"></param>
            public void Set(string path, int fileName)
            {
                Path = path;
                FileName = fileName;
                Time = date.NowSecond;
            }
            /// <summary>
            /// 获取图片路径
            /// </summary>
            /// <param name="fileName"></param>
            /// <returns></returns>
            public string GetPath(ref int fileName)
            {
                if (IsTime)
                {
                    fileName = ++FileName;
                    Time = date.NowSecond.AddMinutes(4);
                    return Path;
                }
                return null;
            }
            /// <summary>
            /// 清除数据
            /// </summary>
            public void Clear()
            {
                Time = DateTime.MinValue;
                Path = null;
            }
        }
        /// <summary>
        /// 考试用户上传图片信息
        /// </summary>
        private static upload[] uploads = new upload[256];
        /// <summary>
        /// 考试用户上传图片信息访问锁
        /// </summary>
        private static readonly object uploadLock = new object();

        /// <summary>
        /// 最大接收消息大小
        /// </summary>
        protected override int maxMessageSize
        {
            get
            {
                return (128 << 10) - (2 + 8 + 4);
            }
        }
        /// <summary>
        /// 过期处理
        /// </summary>
        private void expired()
        {
            int userId = this.userId;
            if (userId != 0)
            {
                userId = sessionId = 0;
                Monitor.Enter(uploadLock);
                uploads[userId].Clear();
                Monitor.Exit(uploadLock);
            }
        }
        /// <summary>
        /// 考试日志消息处理
        /// </summary>
        /// <param name="data"></param>
        protected unsafe override void onMessage(subArray<byte> data)
        {
            byte[] returnData = exceptionData;
            int userId;
            try
            {
                if (data.Count != 0)
                {
                    fixed (byte* dataFixed = data.UnsafeArray)
                    {
                        byte* dataStart = dataFixed + data.StartIndex;
                        switch (*dataStart)
                        {
                            case 0: returnData = null; return;
                            case 1:
                                login(dataStart, data.Count, ref returnData);
                                if ((userId = this.userId) != 0)
                                {
                                    string path = WorkPath + @"upload\examImageServer\" + userId.toString()+ @"\";
                                    int fileName = 0;
                                    if (Directory.Exists(path)) fileName = Directory.GetFiles(path).maxKey(name => int.Parse(name.Substring(name.LastIndexOf('\\') + 1)), 0);
                                    else Directory.CreateDirectory(path);
                                    Monitor.Enter(uploadLock);
                                    if (userId >= uploads.Length)
                                    {
                                        try
                                        {
                                            upload[] newUploads = new upload[Math.Max(uploads.Length << 1, userId + 256)];
                                            Array.Copy(uploads, newUploads, uploads.Length);
                                            uploads = newUploads;
                                            newUploads[userId].Set(path, fileName);
                                        }
                                        finally { Monitor.Exit(uploadLock); }
                                    }
                                    else
                                    {
                                        uploads[userId].Set(path, fileName);
                                        Monitor.Exit(uploadLock);
                                    }
                                }
                                return;
                            case 2:
                                if ((userId = this.userId) == 0 || userId >= uploads.Length || !uploads[userId].IsTime) returnData = null;
                                else
                                {
                                    fastCSharp.net.returnValue<bool> isSessionId = pub.AnswerCacheClient.checkSessionId(userId, this.sessionId);
                                    if (isSessionId.Type == returnValue.type.Success)
                                    {
                                        if (isSessionId.Value)
                                        {
                                            if (uploads[userId].IsTime)
                                            {
                                                bool isImage = false;
                                                using (MemoryStream stream = new MemoryStream(data.UnsafeArray, data.StartIndex + 1, data.Count - 1))
                                                using (Image image = Image.FromStream(stream))
                                                {
                                                    isImage = ((image.Width ^ 320) | (image.Height ^ 240)) == 0 && image.RawFormat.Guid == ImageFormat.Jpeg.Guid;
                                                }
                                                if (isImage)
                                                {
                                                    int fileName = 0;
                                                    Monitor.Enter(uploadLock);
                                                    string path = uploads[userId].GetPath(ref fileName);
                                                    Monitor.Exit(uploadLock);
                                                    if (path != null)
                                                    {
                                                        using (FileStream file = new FileStream(path + fileName.toString(), FileMode.Create))
                                                        {
                                                            file.Write(data.UnsafeArray, data.StartIndex + 1, data.Count - 1);
                                                        }
                                                    }
                                                }
                                                else Console.WriteLine("Web Socket Image Error");
                                            }
                                            returnData = null;
                                        }
                                        else
                                        {
                                            expired();
                                            returnData = verifyExpiredData;
                                        }
                                    }
                                }
                                return;
                            default:
                                Console.WriteLine("Web Socket Type Error");
                                break;
                        }
                    }
                }
                returnData = errorData;
            }
            finally { if (returnData != null) send(returnData); }
        }
    }
}
